﻿namespace ChessToys.ChessController.Cli
{
    using System;
    using System.Collections.Generic;
    using ChessToys.ChessController;

    public class HumanConsoleChessController : AbstractChessController
    {
        private static IList<Position> StartPositions(ISet<Move> moves)
        {
            ISet<Position> starts = new HashSet<Position>();
            foreach (Move move in moves)
            {
                starts.Add(move.Start);
            }
            return new List<Position>(starts);
        }

        private static T Read<T>(IList<T> ts)
        {
            String line = Console.ReadLine();
            try
            {
                int index = int.Parse(line);
                if (index >= 0 && index < ts.Count)
                {
                    return ts[index];
                }
            }
            catch (FormatException)
            {
            }
            return default(T);
        }

        /// <inheritdoc />
        public override Move NextMove(Board board)
        {
            ISet<Move> possibleMoves = MoveGeneratorUtils.PossibleMoves(board, board.ColorToMove);
            Position start = ReadStartPosition(StartPositions(possibleMoves), board);
            // filter possible moves for start position
            foreach (Move move in new HashSet<Move>(possibleMoves))
            {
                if (move.Start != start)
                {
                    possibleMoves.Remove(move);
                }
            }
            Move nextMove = ReadNextMove(new List<Move>(possibleMoves), board);
            return nextMove;
        }

        private Move ReadNextMove(IList<Move> possibleMoves, Board board)
        {
            Move nextMove = null;
            while (nextMove == null)
            {
                Console.WriteLine();
                Console.WriteLine("Enter next move:");
                for (int i = 0; i < possibleMoves.Count; i++)
                {
                    Move move = possibleMoves[i];
                    Console.WriteLine(String.Format(" {0}: {1}", i, move.ToString(board)));
                }
                nextMove = Read<Move>(possibleMoves);
            }
            return nextMove;
        }

        private Position ReadStartPosition(IList<Position> startPositions, Board board)
        {
            Position start = null;
            while (start == null)
            {
                Console.WriteLine();
                Console.WriteLine("Enter start position:");
                for (int i = 0; i < startPositions.Count; i++)
                {
                    Console.WriteLine(String.Format(" {0}: {1}", i, startPositions[i].ToString(board)));
                }
                start = Read<Position>(startPositions);
            }
            return start;
        }
    }
}
